package com.inspur.edp.bef.bemanager.service.cdmparser;


//using Common.Logging;

import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import lombok.var;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class CdmReader {

    ///#region 字段属性
//    private final ParserUtil Util = new ParserUtil();
    private String pdmFile;
    private java.util.List<CdmTableInfo> tables;
    private java.util.List<CdmColumnInfo> dataItems;
    private Document xmlDoc;
//    private XmlNamespaceManager xmlnsManager;
//    private Regex regex;

    private CdmReader() {
        // TODO: 在此处添加构造函数逻辑
        //xmlDoc = new XmlDocument();
        //xmlDoc = new XmlDocument();
        //xmlDoc.Load(pdmFile);
        //xmlnsManager = new XmlNamespaceManager(xmlDoc.NameTable);
        //xmlnsManager.AddNamespace("a", "attribute");
        //xmlnsManager.AddNamespace("c", "collection");
        //xmlnsManager.AddNamespace("o", "object");
        //XmlNode xnTables = xmlDoc.SelectSingleNode("//" + cTables, xmlnsManager);
    }

    public CdmReader(String xml) {
        this();
        if (xmlDoc == null) {
            try {
                xmlDoc = DocumentHelper.parseText(xml);
            } catch (DocumentException e) {
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0001, e, "CDM Text");
            }
//			xmlDoc = new XmlDocument();
//			xmlDoc.InnerXml = xml;
//            xmlnsManager = new XmlNamespaceManager(xmlDoc.NameTable);
//            xmlnsManager.AddNamespace("a", "attribute");
//            xmlnsManager.AddNamespace("c", "collection");
//            xmlnsManager.AddNamespace("o", "object");
        }
        initData();
    }


    ///#endregion


    ///#region 构造函数

    public final String getPdmFile() {
        return pdmFile;
    }

    public final java.util.List<CdmTableInfo> getTables() {
        return tables;
    }


    ///#endregion

    public final java.util.List<CdmColumnInfo> getDataItems() {
        return dataItems;
    }


    ///#region table

    private void initData() {
        // 读取字段集合
        if (dataItems == null) {
            dataItems = new java.util.ArrayList<CdmColumnInfo>();
            Element xnDataItems = ((Element) xmlDoc.getRootElement().selectSingleNode("//" + CdmNames.cDataItems));
            for (Element xnTable : xnDataItems.elements()) {
                dataItems.add(getColumn(xnTable));
            }
//			dataItems = new java.util.ArrayList<CdmColumnInfo>();
//			XmlNode xnDataItems = xmlDoc.SelectSingleNode("//" + CdmNames.cDataItems, xmlnsManager);
//			for (XmlNode xnTable : xnDataItems.ChildNodes)
//			{
//				dataItems.add(GetColumn(xnTable));
//			}
        }

        // 读取表
        if (tables == null) {
            tables = new java.util.ArrayList<CdmTableInfo>();
            Element xnDataItems = ((Element) xmlDoc.getRootElement().selectSingleNode("//" + CdmNames.cEntities));
            for (Element xnTable : xnDataItems.elements()) {
                tables.add(getTable(xnTable));
            }

//            XmlNode xnTables = xmlDoc.SelectSingleNode("//" + CdmNames.cEntities, xmlnsManager);
//            for (XmlNode xnTable : xnTables.ChildNodes) {
//                getTables().add(GetTable(xnTable));
//            }
        }

    }


    ///#endregion


    ///#region columns

    private CdmTableInfo getTable(Element xnTable) {
        CdmTableInfo mTable = new CdmTableInfo();
//        XmlElement xe = (XmlElement) xnTable;
        String tableId = xnTable.attribute("Id").getValue();
//        mTable.setTableId(xe.GetAttribute("Id"));
        mTable.setTableId(tableId);
//        XmlNodeList xnTProperty = xe.ChildNodes;
        for (Element xnP : xnTable.elements()) {
            switch (xnP.getQName().getQualifiedName()) {
                case CdmNames.aObjectID:
                    mTable.setObjectID(xnP.getStringValue());
                    break;
                case CdmNames.aName:
                    mTable.setName(xnP.getStringValue());
                    break;
                case CdmNames.aCode:
                    mTable.setCode(xnP.getStringValue());
                    break;
                case CdmNames.aCreationDate:
                    mTable.setCreationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aCreator:
                    mTable.setCreator(xnP.getStringValue());
                    break;
                case CdmNames.aModificationDate:
                    mTable.setModificationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aModifier:
                    mTable.setModifier(xnP.getStringValue());
                    break;
                case CdmNames.aComment:
                    mTable.setComment(xnP.getStringValue());
                    break;
                case CdmNames.aPhysicalOptions:
                    mTable.setPhysicalOptions(xnP.getStringValue());
                    break;
                case CdmNames.cAttributes:
                    initColumns(xnP, mTable);
                    break;
                case CdmNames.aIdentifiers:
                    initKeys(xnP, mTable);
                    break;
                case CdmNames.cPrimaryIdentifier:
                    //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, "o:Identifier");
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
                    Element idNode = xnP.elements().stream().findFirst().get();
                    mTable.setPrimaryItemId(getRefItemId(idNode));
                    break;
            }
        }
        return mTable;
    }

    private void initColumns(Element xnColumns, CdmTableInfo pTable) {
        for (Element xnColumn : xnColumns.elements()) {
            CdmColumnInfo columnInfo = getColumn(xnColumn);
            updateTableColumnsInfo(columnInfo);
            pTable.addColumn(columnInfo);
        }
    }

    private CdmColumnInfo getColumn(Element xnColumn) {
        CdmColumnInfo mColumn = new CdmColumnInfo();
//		XmlElement xe = (XmlElement)xnColumn;
        String columnId = xnColumn.attribute("Id").getValue();
//		mColumn.setColumnId(xe.GetAttribute("Id"));
        mColumn.setColumnId(columnId);
//		XmlNodeList xnCProperty = xe.ChildNodes;
        for (Element xnP : xnColumn.elements()) {
            switch (xnP.getQName().getQualifiedName()) {
                case CdmNames.aObjectID:
                    mColumn.setObjectID(xnP.getStringValue());
                    break;
                case CdmNames.aName:
                    mColumn.setName(xnP.getStringValue());
                    break;
                case CdmNames.aCode:
                    mColumn.setCode(xnP.getStringValue());
                    break;
                case CdmNames.aCreationDate:
                    mColumn.setCreationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aCreator:
                    mColumn.setCreator(xnP.getStringValue());
                    break;
                case CdmNames.aModificationDate:
                    mColumn.setModificationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aModifier:
                    mColumn.setModifier(xnP.getStringValue());
                    break;
                case CdmNames.aComment:
                    mColumn.setComment(xnP.getStringValue());
                    break;
                case CdmNames.aDataType:
                    mColumn.setDataType(getDataType(xnP.getText()));
                    break;
                case CdmNames.aLength:
                    String length = xnP.getText();
                    mColumn.setLength(isNullOrEmpty(length) ? "0" : length);
                    break;
                case CdmNames.aPrecision:

                    String precision = xnP.getText();
                    mColumn.setPrecision(isNullOrEmpty(precision) ? "0" : precision);
                    break;
                case CdmNames.aIdentity:
                    //mColumn.Identity = pgConvert.ConvertToBooleanPG(xnP.InnerText);
                    break;
                case CdmNames.aMandatory:
                    //mColumn.Mandatory = pgConvert.ConvertToBooleanPG(xnP.InnerText);
                    break;
                case CdmNames.aPhysicalOptions:
                    mColumn.setPhysicalOptions(xnP.getStringValue());
                    break;
                case CdmNames.aExtendedAttributesText:
                    mColumn.setExtendedAttributesText(xnP.getStringValue());
                    break;
                case CdmNames.cDataItem:
                    //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, oDataItem);
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
                    Element idNode = (Element) xnP.elements().stream().findFirst().get();
                    mColumn.setRefItemId(getRefItemId(idNode));
                    break;
            }
        }
        return mColumn;
    }


    ///#endregion

    private void updateTableColumnsInfo(CdmColumnInfo columnInfo) {
        if (columnInfo == null) {
            return;
        }
        String refItemId = columnInfo.getRefItemId();
        if (!isNullOrEmpty(refItemId)) {

            var items = dataItems.stream().filter((item) -> {
                return refItemId.equals(item.getColumnId());
            }).toArray();

            if (items.length == 0) {
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0026);
            }

            CdmColumnInfo dataItem = (CdmColumnInfo) items[0];
            String length = dataItem.getLength();
            columnInfo.setLength(isNullOrEmpty(length) ? "0" : length);
            String precision = dataItem.getPrecision();
            columnInfo.setPrecision(isNullOrEmpty(precision) ? "0" : precision);
            columnInfo.setDataType(dataItem.getDataType());
            columnInfo.setCode(dataItem.getCode());
            columnInfo.setName(dataItem.getName());
        }
    }

    ///#region keys
    private void initKeys(Element xnKeys, CdmTableInfo pTable) {
        for (Element xnKey : xnKeys.elements()) {
            pTable.addKey(getKey(xnKey));
        }
    }

    ///#endregion


    ///#region util

    private CdmKey getKey(Element xnKey) {
        CdmKey mKey = new CdmKey();
//        XmlElement xe = (XmlElement) xnKey;
        String keyId = xnKey.attribute("Id").getValue();
//        mKey.setKeyId(xe.GetAttribute("Id"));
        mKey.setKeyId(keyId);
//        XmlNodeList xnKProperty = xe.ChildNodes;
        for (Element xnP : xnKey.elements()) {
            switch (xnP.getQName().getQualifiedName()) {
                case CdmNames.aObjectID:
                    mKey.setObjectID(xnP.getStringValue());
                    break;
                case CdmNames.aName:
                    mKey.setName(xnP.getStringValue());
                    break;
                case CdmNames.aCode:
                    mKey.setCode(xnP.getStringValue());
                    break;
                case CdmNames.aCreationDate:
                    mKey.setCreationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aCreator:
                    mKey.setCreator(xnP.getStringValue());
                    break;
                case CdmNames.aModificationDate:
                    mKey.setModificationDate(Integer.parseInt(xnP.getText()));
                    break;
                case CdmNames.aModifier:
                    mKey.setModifier(xnP.getStringValue());
                    break;
                case CdmNames.cIdentifierAttributes:
                    //XmlElement idNode = (XmlElement)Util.GetChildNode(xnP, "o:EntityAttribute");
//                    XmlElement idNode = (XmlElement) xnP.ChildNodes[0];
                    Element idNode = xnP.elements().stream().findFirst().get();
                    mKey.setRefItemId(getRefItemId(idNode));
                    break;
            }
        }
        return mKey;
    }

    private String getTypeString(String s) {

        return s.replaceAll("[^(A-Za-z)]", "");

//        if (regex == null) {
//            String typeStringPattern = "[a-z]*[A-Z]*";
//            regex = new Regex(typeStringPattern);
//
//        }
////        Pattern patternAlphaNumericCheck = Pattern.compile("^[a-zA-Z0-9]$");
////        Matcher matcherAlphaNumericCheck = patternAlphaNumericCheck.matcher(login.getPassword());
//        String result = regex.Match(s).toString();
//        if (isNullOrEmpty(result)) {
//            throw new BeManagerException(exceptionCode, "类型不正确。");
//        }
//        return result;
    }

    private GspElementDataType getDataType(String s) {
        String type = getTypeString(s);

        if (CdmNames.CdmDataType_Image.equals(type) || CdmNames.CdmDataType_LongBinary.equals(type) || CdmNames.CdmDataType_Ole.equals(type) || CdmNames.CdmDataType_Multibyte.equals(type) || CdmNames.CdmDataType_VarMultibyte.equals(type) || CdmNames.CdmDataType_Binary.equals(type) || CdmNames.CdmDataType_Bitmap.equals(type) || CdmNames.CdmDataType_VariableBinary.equals(type)) {
            return GspElementDataType.Binary;

        } else if (CdmNames.CdmDataType_Boolean.equals(type)) {
            return GspElementDataType.Boolean;

        } else if (CdmNames.CdmDataType_Date.equals(type)) {
            return GspElementDataType.Date;

        } else if (CdmNames.CdmDataType_DateTime.equals(type) || CdmNames.CdmDataType_Time.equals(type) || CdmNames.CdmDataType_TimeStamp.equals(type)) {
            return GspElementDataType.DateTime;

        } else if (CdmNames.CdmDataType_Float.equals(type) || CdmNames.CdmDataType_LongFloat.equals(type) || CdmNames.CdmDataType_ShortFloat.equals(type) || CdmNames.CdmDataType_Decimal.equals(type) || CdmNames.CdmDataType_Money.equals(type) || CdmNames.CdmDataType_Number.equals(type)) {
            return GspElementDataType.Decimal;

        } else if (CdmNames.CdmDataType_Integer.equals(type) || CdmNames.CdmDataType_LongInteger.equals(type) || CdmNames.CdmDataType_ShortInteger.equals(type) || CdmNames.CdmDataType_Serial.equals(type) || CdmNames.CdmDataType_Byte.equals(type)) {
            return GspElementDataType.Integer;

        } else if (CdmNames.CdmDataType_Char.equals(type) || CdmNames.CdmDataType_VarCha.equals(type) || CdmNames.CdmDataType_LongCha.equals(type) || CdmNames.CdmDataType_LongVarCha.equals(type)) {
            return GspElementDataType.String;

        } else if (CdmNames.CdmDataType_Text.equals(type)) {
            return GspElementDataType.Text;
        } else {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0027, type);
        }
    }

    private String getRefItemId(Element xe) {
//        return xe.GetAttribute("Ref");
        return xe.attribute("Ref").getValue();
    }


    ///#endregion

    public final CdmTableInfo FindTableByTableName(String tableName) {
        return FindTableByCode(tableName);
    }

    public final CdmTableInfo FindTableByCode(String tableCode) {
        for (CdmTableInfo mTable : tables) {
            if (mTable.getCode().equals(tableCode)) {
                return mTable;
            }
        }
        return null;
    }

    private boolean isNullOrEmpty(String str) {
        return str == null || "".equals(str);
    }
}